package org.gpp.proj1.camera.action;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;

/**
 * 
 * @author Paolo Victor, paolovictor@gmail.com
 */
public class LookAtPointAction implements CameraAction {
	
	/**
	 * The time passed since the action start
	 */
	private float elapsedTime;
	
	/**
	 * The action's duration
	 */
	private float actionDuration;

	/**
	 * Defines if the action is finished
	 */
	private boolean finished;

	/**
	 * The quaternion that represents the direction
	 * that the camera will be facing on the action's end
	 */
	private Quaternion targetQuaternion;

	/**
	 * The quaternion that represents the camera's
	 * initial direction
	 */
	private Quaternion initialRotation;

	private CameraNode camera;

	private Vector3f point;
	
	public LookAtPointAction( CameraNode camera, Vector3f point, float actionDuration ) {
		this.finished = false;
		this.elapsedTime = 0.0f;
		this.actionDuration = actionDuration;
		
		this.camera = camera;
		this.point = point;
	}
	

	public void updateAction(float timePerFrame, CameraNode cameraNode ) {
		// If finished, do nothing
		if( finished ) {
			return;
		}
		
		// If it's the first iteration, get initial rotation
		if( elapsedTime == 0.0f ) {
			this.initialRotation = new Quaternion( camera.getLocalRotation() );
			
			Node node = new Node("Dummy");
			node.setLocalRotation( camera.getLocalRotation() );
			node.setLocalTranslation( camera.getLocalTranslation() );
			
			node.lookAt( point, new Vector3f( 0, 1, 0 ) );
			node.updateGeometricState( 0.0f, true );
				
			this.targetQuaternion = new Quaternion( node.getLocalRotation() );
			
			camera.setLocalRotation( initialRotation );
			camera.updateGeometricState( 0.0f, true );
		}
		
		
		// Updating ticks and rotating camera node towards point
		elapsedTime += timePerFrame;
		
		if( elapsedTime >= actionDuration ) {
			finished = true;
			cameraNode.getLocalRotation().set( targetQuaternion );
			cameraNode.getLocalRotation().normalize();
			cameraNode.updateGeometricState( 0.0f, true );
			return;
		}
		
		Quaternion localRotation = new Quaternion( cameraNode.getLocalRotation() );
		
		localRotation.set( initialRotation );
		localRotation.slerp( targetQuaternion, elapsedTime / actionDuration );
		localRotation.normalize();
		
		cameraNode.setLocalRotation( localRotation );
		cameraNode.updateGeometricState( 0.0f, true );
	}

	public boolean isFinished() {
		return finished;
	}

}
